<template>
  <div v-if="!isEmpty" class="column-bar w-full h-full" ref="horizontalColumnChart"></div>
</template>

<script lang="ts" setup>
import { defineComponent, markRaw, onMounted, onBeforeUnmount, ref, watch } from 'vue';
import * as echarts from 'echarts';
import { sleep } from '@/utils/sleep';
import top1 from './assets/top1.png';
import top2 from './assets/top2.png';
import top3 from './assets/top3.png';
import topOther from './assets/top-other.png';

defineComponent({ name: 'HorizontalColumnChart' });

const props = defineProps({
  echartsData: {
    type: Array,
    default: () => {
      return [];
    },
  },
  graphicColor: {
    type: Array,
    default: () => {
      return ['rgba(0, 98, 199, 1)', 'rgba(0, 233, 248, 1)'];
    },
  },
  barWidth: {
    type: String,
    default: '12',
  },
  yAxisLabel: {
    type: Object,
    default: () => {
      return { grid: { left: '-90' }, axisLabel: { width: 220, margin: 140 } };
    },
  },
});

const isEmpty = ref(false);
const horizontalColumnChart = ref();
const myChart = ref<any>(null);
const observer = ref<ResizeObserver>();
const timer = ref<any>(null)

function initEcharts(data: any[]) {
  if (myChart.value) destroyEcharts();
  const graphicColor: any[] = props.graphicColor || [];
  const barWidth = props.barWidth;
  const dataValue = data.map((item: any) => item.value);
  const max = Math.max(...dataValue);
  const maxData: number[] = dataValue.map(() => max);
  // 标记一个对象，使其永远不会再成为响应式对象
  myChart.value = markRaw(echarts.init(horizontalColumnChart.value));
  const option = {
    grid: {
      top: '20',
      left: props.yAxisLabel.grid.left,
      right: '10',
      bottom: '20',
      containLabel: true,
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow',
      },
      backgroundColor: 'rgba(0,150,236,0.6)',
      textStyle: {
        color: '#fff',
      },
      formatter: function (params: any) {
        return (
          params[0].name +
          '<br/>' +
          "<span style='display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:rgba(36,207,233,0.9)'></span>" +
          params[0].seriesName +
          Number(params[0].value.toFixed(4)).toLocaleString() +
          '<br/>'
        );
      },
    },
    xAxis: {
      type: 'value',
      minInterval: 1,
      max: 100,
      splitLine: {
        show: false,
      },
      axisTick: {
        show: false,
      },
      axisLabel: {
        show: false,
      },
    },
    yAxis: [
      {
        type: 'category',
        triggerEvent: true,
        inverse: true,
        axisLabel: {
          show: true,
          color: '#fff',
          align: 'left',
          width: props.yAxisLabel.axisLabel.width,
          overflow: 'truncate',
          ellipsis: '...',
          margin: props.yAxisLabel.axisLabel.margin,
          rich: {
            bg1: getRich(0),
            bg2: getRich(1),
            bg3: getRich(2),
            bg_other: getRich(3),
            b: {
              fontSize: 14,
              padding: [0, 100, 0, 30],
            },
          },
          formatter: (v: string, i: number) => {
            if (i === 0) {
              return `{bg1|${i + 1}}{b|${v}}`;
            } else if (i === 1) {
              return `{bg2|${i + 1}}{b|${v}}`;
            } else if (i === 2) {
              return `{bg3|${i + 1}}{b|${v}}`;
            } else {
              return `{bg_other|${i + 1}}{b|${v}}`;
            }
          },
        },
        splitLine: {
          show: false,
        },
        axisTick: {
          show: false,
        },
        axisLine: {
          show: false,
        },
        data: data.map((item: any) => item.name),
      },
      {
        type: 'category',
        inverse: true,
        axisTick: 'none',
        axisLine: 'none',
        show: false,
        axisLabel: {
          color: '#333',
          fontSize: '16',
        },
        data: dataValue,
      },
    ],
    series: [
      {
        name: '',
        type: 'bar',
        zlevel: 1,
        itemStyle: {
          normal: {
            barBorderRadius: 30,
            color: (params: any) => {
              if(params.dataIndex < 3) {
                return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                  {
                    offset: 0,
                    color: 'rgba(76, 42, 5, 1)',
                  },
                  {
                    offset: 1,
                    color: 'rgba(250, 173, 40, 1)',
                  },
                ])
              } else {
                return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                  {
                    offset: 0,
                    color: 'rgba(10, 44, 85, 1)',
                  },
                  {
                    offset: 1,
                    color: 'rgba(48, 175, 239, 1)',
                  },
                ])
              }
            }
          }
        },
        label: {
          normal: {
            show: true,
            color: '#fff',
            fontSize: 16,
            position: 'left',
            formatter: '{c}',
          },
        },
        barWidth,
        data: dataValue,
      },
      {
        name: '背景',
        type: 'bar',
        barWidth,
        barGap: '-100%',
        data: maxData,
        itemStyle: {
          color: 'rgba(106, 118, 136, 0.3)',
          // borderRadius: 8,
        },
      },
      // {
      //   name: '背景2',
      //   type: 'bar',
      //   barWidth: '16',
      //   barGap: '-130%',
      //   data: maxData,
      //   itemStyle: {
      //     color: 'rgba(47, 64, 79, 0.4)',
      //     // borderRadius: 8,
      //   },
      // },
    ],
  };
  myChart.value.setOption(option, true);
  let i = -1;
  timer.value = setInterval(() => {
    i = i === dataValue.length ? 0 : i + 1;
    myChart.value.dispatchAction({
      type: "showTip",
      seriesIndex: 0, // 显示第几个series
      dataIndex: i, // 显示第几个数据
    });
  }, 2000);
  window.addEventListener('resize', () => {
    if (myChart.value) myChart.value.resize();
  });
}

function getRich(i: number) {
  const bg = [top1, top2, top3, topOther];
  const color = ['#D42121', '#C24400', '#CD6402', '#7A7E94'];
  return {
    backgroundColor: {
      image: bg[i],
    },
    width: 16,
    height: 22,
    color: color[i],
    fontSize: 16,
    fontWeight: 700,
    padding: [2, 0, 0, 8],
  };
}

function destroyEcharts() {
  if (myChart.value) {
    myChart.value.dispose();
    myChart.value = null;
  }

  if (timer.value) {
    clearInterval(timer.value);
    timer.value = null;
  }
}

onMounted(() => {
  watch(
    () => props.echartsData,
    async (val: any[]) => {
      isEmpty.value = !val.length;
      await sleep(500);
      if (!isEmpty.value && horizontalColumnChart.value) initEcharts(val);
    },
    { immediate: true, deep: true }
  );
});

onBeforeUnmount(() => {
  destroyEcharts();
  // 在组件卸载时停止监听，避免内存泄漏
  observer.value?.disconnect();
});
</script>

<style scoped></style>
